from time import clock
from bond import Bond
from loa_game import WHITE, BLACK, LinesOfActionState
from loa_example import AlphaBetaAgent
from modified_alpha_beta import ModifiedAlphaBetaSearch
from experimentClass.TestTimebond import TestTimeBond

class GameRunner():
    '''
    Runs a game.
    '''
    
    def __init__(self, initial_state, agents, turn_time_limit, setup_time_limit):
        '''
        Constructor.
        
        @param initial_state: The initial game state.
        @param agents: A dictionary that maps players to their agents.
        @param turn_time_limit: The time limit of each turn.
        @param setup_time_limit: The time limit for setting up the agent.
        '''
        self.initial_state = initial_state
        self.agents = agents
        self.turn_time_limit = turn_time_limit
        self.setup_time_limit = setup_time_limit
        self.updateTime = []
        self.setupTime  = []
        self.turnTimes   = []
    
    def run(self):
        '''
        Runs the game. Prints actions and states.
        
        @return: The game's winner.
        '''
        for player, agent in self.agents.items():
            start = clock()
            agent.setup(player, self.initial_state, self.turn_time_limit, self.setup_time_limit)
            setup_time = clock() - start
            if setup_time > self.setup_time_limit:
                raise Exception(str(player) + ' failed to set up in time.')
        
        state = self.initial_state
        while state.getWinner() is None:
            agent = self.agents[state.getCurrentPlayer()]
            start = clock()
            action = agent.move(state)
            turn_time = clock() - start
            print "Turn Time was: ", turn_time
            if isinstance(agent, TestTimeBond):
                self.turnTimes.append(turn_time)
                self.updateTime.append(agent.alphaBeta.utilDataUpdateTime)
                print "++Update time was: ", agent.alphaBeta.utilDataUpdateTime
                print "++Update radio was : ",  100*float(agent.alphaBeta.utilDataUpdateTime)/turn_time
                print "==="
                self.setupTime.append(agent.alphaBeta.setupTime)
                print "++Setup time was: ", agent.alphaBeta.setupTime
                print "++Setup time ratio: ", 100*float(agent.alphaBeta.setupTime)/turn_time
            if turn_time > self.turn_time_limit and isinstance(agent, Bond):
                raise Exception(str(state.getCurrentPlayer()) + ' failed to return a move in time.')
            
            successors = state.getSuccessors()
            if action not in successors.keys():
                raise Exception(str(state.getCurrentPlayer()) + ' made an illegal move.')
            
            state = successors[action]
            
            print action
            print state
        print 'number of turns', state.turns_left
        return state.getWinner()

 
#agents = {}
#agents[WHITE] = TestTimeBond()
#agents[BLACK] = AlphaBetaAgent()
#
#state = LinesOfActionState(7, 50)
#
#print "Starting Game...."
#winner = GameRunner(state, agents, 5, 1).run()
#print "root cache hit number = ", ModifiedAlphaBetaSearch.root_cache_hit
#print "root cache hit rate = ", float(ModifiedAlphaBetaSearch.root_cache_hit)/(ModifiedAlphaBetaSearch.root_cache_hit + ModifiedAlphaBetaSearch.root_cache_miss)
#print "leaves cache hit number = ", ModifiedAlphaBetaSearch.leaves_cache_hit
#print "leaves cache hit rate = ", float(ModifiedAlphaBetaSearch.leaves_cache_hit)/(ModifiedAlphaBetaSearch.leaves_cache_hit + ModifiedAlphaBetaSearch.leaves_cache_miss) 
#print 'Winner:', winner 